/**
 * @file circuit_config.h
 * @author Linquan  
 * @brief  回路节点配置：回路ID、IO操作功能码、回路节点类型（所支持的设备类型）、回路类型、、回路节点操作函数、
 * @version 1.0
 * @date 2024-08-10
 * 
 * @copyright Copyright (c) 2024
 * 
 */

#ifndef CIRCUIT_CONFIG_H
#define CIRCUIT_CONFIG_H

  /** TODO: 另开一个头文件，用于放这里所有的可配置设备信息：
         *  包括：
         * √设备类型号
         * √ 不同设备节点配置信息结构
         *  √ TODO: 这个配置信息需要根据设备模块给出，要引入设备模块而不是单独拎出来设计
         *   √ TODO:  这些设备模块，需要提供：基本设备信息（固定）、设备实时运行数据、设备配置参数、设备操作接口等内容
         *              设备基本信息，所有设备通用，后两个根据设备而定。
         *        设备模块的操作接口： init初始化、reset复位、报文解析。
         *              然后对于 
         *              IO控制（对外控制） ，函数传参得有：设备节点、功能码、传入信息
         *              write（request发送请求，并parse协议解析写入信息） 
         *              read（设置或读取设备节点自身运行信息，这里写入可以用报文解析来代替）。
         *      read函数传参得有：设备节点、功能码、读出信息的存储位置。这个读出的存储位置，用{设备类型，设备的实时参数结构}组成。
         *          假如每个设备的控制码都有区别，或者可以同时读取不同种数据那该如何设计。
         * 
         * √ 配置文件给出配置所需要的IO控制功能码，这一部分需要固定，程序内外一致。但是需不需要抽象？是否要把io控制码集合在一起。用。
         *      由于90A目前需求不多，可以考虑集合在一起，内外一致：操作码先定为：启动、停止、读取设备实时数据信息。以后的事以后再说。
         * 
         * √上边的io操作功能码、
         * √这里的总线报文格式、
         * 
         * 
         * 获取设备具体信息的途径的发报文，分为了主动上报和请求发送。是否要在设备配置中增加是否主动上报的配置选项？不用，
         *    在设备初始化时，根据设备种类来判断是否上报，然后建一个数组，用来保存需要请求的设备地址。最后遍历这个设备表来对外发送请求报文。
         *   那么 是否主动上报、是否需要判离线。这两种配置就用设备类型来决定，当需要判离线的设备初始化时，提供一个往判离线的数组里添加节点的函数接口。、
         *              把这个要判离线的设备节点的地址送进去。（这个数组里放的设备节点的指针，遍历的时候，在数组遍历这些指针）   
         * 
         * 
         * busmap中 每个节点的配置内容 都从一个配置表中获得。使用模块的init函数进行配置。传入busmap的设备节点指针和配置表中该节点的配置信息。
         *  总之，想办法用外部信息或者 手写的方式形成一张配置表，然后用这个配置表配置节点信息。
         *  配置表分为两种，一种是主配置表给90A用，另一种是从配置表，给90A连接的从控制器用。一份主配置表、可能多份从配置表。
         * 
         * 在circuit_node.c 中放 系统设备管理指针吧，与节点设备初始化及操作函数都放这个文件中吧。
         *      这些函数是负责把配置信息填入节点配置中。遍历回路节点放在busmap.c中。这个文件就提供 操作节点的函数：
         *          busmap中把自己的回路节点指针放入操作函数，这里的circuit_node.c中的函数负责给装配置信息。
         *          busmap传入一个节点，这里要负责 找到这个节点的类型，并找到对应的操作函数进行数据操作。  
         * 
         * 
         * 在busmap中，还要设置 request数组、离线检测数组。这些数组的填充要在busmap节点初始化时进行填充。
         *      填充方式可以用节点init函数的返回值，在把配置信息写入busmap节点后（应该叫circuit——map吧）
         *          通过一个返回值来判断是否需要单独请求、是否需要检测离线.
         *         比如定义 第0位为1表示配置信息出错，第1位为1表示需要单独请求，第2位为1表示需要检测离线。最大定义32位标志位。
         * 
         * 
         * 
         * 
         * 
         * 
         * 
         * 
         */

/*===========================[Includes]======================================*/
#include "stdint.h"
#include <string.h>
#include <stdlib.h>

#include "macro_config.h"
#include "../config/config_struct.h"

/*===========================[Defines]=======================================*/
/*===========================[Macros]========================================*/

/**> 初始化函数的返回值 */
#define NOR_OFFSET(X)               (1<<(X))    // 低8位表示 特殊处理
#define ERR_OFFSET(X)               (1<<(X+8))  // 高8位表示 错误类型
#define ERR_MASK                    0XFFFFFF00


#define INIT_NEED_REQUEST            NOR_OFFSET(0)
#define INIT_NEED_CHECK_OFFLINE      NOR_OFFSET(1)


#define INIT_ERR_CONFIG             ERR_OFFSET(0) 
#define INIT_ERR_TYPE               ERR_OFFSET(1)
#define INIT_ERR_NODE_NULL          ERR_OFFSET(2)


/**> 操作函数的返回值 */

#ifndef OP_RESULT_CODE
#define OP_SUCCESS              0

#define OP_FAIL_PTR_NULL        1
#define OP_FAIL_OVERSTEP        2
#define OP_TYPE_ERR             3

#define OP_NOT_SUPPORT         -1

#endif





/*===========================[Typedef]=======================================*/



/**
 * @brief 回路类型和回路ID对应关系,
 *  设备自身的回路ID
 *  想在哪个回路挂设备，就得填哪个回路id。
 * circuit
 */
typedef enum {
    SELF_CIRCUIT_CAN_IN1 = 0,
    SELF_CIRCUIT_CAN_OUT1,

    SELF_CIRCUIT_RS485_IN1,
    SELF_CIRCUIT_RS485_OUT1,

   
    

    // 以下全部按照回路+节点来进行管理，目前可能还用不到这些回路。
    // SELF_CIRCUIT_DRY_POINT,  /**> 干节点 */
    // SELF_CIRCUIT_ETH0,       /**> 网口0 */
    // SELF_CIRCUIT_ETH1,       /**> 网口1 */
    // 这里留着，以后 如果有90A当做99A使用的时候，可以启用。 
    // SELF_CIRCUIT_EXTH_SPRAING,    // 灭火器喷洒策略回路
    // SELF_CIRCUIT_PROTECT_ZONE,    // 防护区集合和路
    
    SELF_CIRCUIT_MAX
} self_circuit_ID_t;





/**
 * @brief IO控制函数的操作码
 * 
 */
typedef enum
{
    /// @brief  通用型操作码

    OP_CODE_STOP  = 0X00, // 编号固定不变，内外一致
    OP_CODE_ACTIVE ,   // 编号固定不变，内外一致

    //操作种类对于设备只会有一种情况，否则就设置特殊型操作码

    OP_CODE_READ_ALL = 0X100, /**读取节点全部信息 */
    OP_CODE_READ_RT_DATA,     /** 读取节点实时状态 */
    OP_CODE_READ_PRIFILE,     /** 读取节点配置信息 */
    OP_CODE_FIND_NODE,


    /// @brief  特殊型操作码，根据设备独立需求设置。
    // 范围：0X1000 - 0XFFFF
    OP_CODE_90A_EVENT_LIST_ADD = 0x1000, /**> 90A 向气灭分区链表添加事件 */
    //OP_CODE_90A_EVENT_LIST_GET,          /**> 90A 获取气灭分区链表头 */


}operate_code_t;






/**
 * @brief 回路节点类型枚举
 * 列举本产品 可以配置的节点类型
 * 格式： 产品大类_产品型号_产品子版本(如果有的话)
 */
typedef enum
{
    TYPE_SENSOR_07A_SLAVE = 0X1,  /** 探测器 07a 主从式 */
    
    TYPE_SENSOR_SMOKE,                   /** 探测器：感烟 */
    TYPE_SENSOR_TEMPERATURE,             /** 探测器：感温 */

    TYPE_SWITCH_URGENT_SWITCH,           /** 紧急启停 */

    TYPE_MOD_IO_DRY,                     /** 模块 输入输出 无源 */
    TYPE_MOD_LIGHT_ALARM,
    TYPE_MOD_GAS_NOT_IN,
    TYPE_MOD_RELAY,                      /** 中继模块 */

    TYPE_CTR_CW1320_91A,              /** 91A仓级主机 */

    TYPE_SENSOR_H2,
    TYPE_SENSOR_CO,

    TYPE_DRY_POINT_IN,
    TYPE_DRY_POINT_OUT,

    TYPE_EXTI_PRESS,
    TYPE_PROTECT_ZONE,

}circuit_node_type_t;





/**
 * @brief  真实回路类型
 * 
 * 
 */
typedef enum {
    KIND_CAN_PROT,
    KIND_RS485_PROT,
    KIND_ETH_PORT,
    KIND_DRY_POINT,
    KIND_ERR
} really_circuit_kind_t;







/**
 * @brief 节点地址
 *  这里传入的值 是相对于回路的，回路ID+这个回路上的第几个节点，
 *  这个节点的索引都是从0开始计数，节点索引号和节点所拥有的节点地址是不相关的，回路1，节点2，可能代表了 13号控制器。
 */
typedef struct {

    uint32_t  circuit_ID;            /* 回路ID */
    uint32_t  circuit_node_index;   /* 回路节点索引号 */ 
       
}circuit_node_addr_t;



/**
 * @brief 设备操作接口
 * @attention irfReset 复位
 *      不同与irfInit，irfInit可能触发新的任务/线程的产生，而复位并不需要这些操作
 * @attention irfIoCtrl IO操作
 *      1. 该接口的参考需要根据具体设备类型进行设置，具体设备的该接口注意
 *      2. 该接口返回0表示成功，返回>0 表示解析失败，返回-1 表示不支持
 * @attention irfProtlParse 协议解析
 *      1. 返回0时，表示成功，-1为不支持协议，>0表示解析失败
 *      2. 当ENU_PROT_KIND为CAN_PORT，数据结构为struct can_frame *
 */
typedef struct
{
    uint32_t (*irfInit)(void *node_ptr, void *profile_ptr);
    void (*irfReset)(void *node_ptr);
    int32_t (*irfIoCtrl)(void *node_ptr, operate_code_t op_code, void * op_data);

    void (*irfRequest)(void *);
    int32_t (*irfProtParse)(void *node_ptr, really_circuit_kind_t kind_bus, void *fram_data, uint16_t len);
} node_operate_irf_t;



/*===========================[Global Prototypes]=============================*/


/**
 * @brief Get the op irf by circuit node type object
 *  根据回路节点类型获得操作函数
 * @return node_operate_irf_t 
 */
 node_operate_irf_t*  get_op_irf_by_circuit_node_type(circuit_node_type_t type);




/**
 * @brief Get the circuit kind object
 *  根据回路ID来获得真实回路的端口类型
 * @param id 
 * @return really_circuit_kind_t 
 */
really_circuit_kind_t get_circuit_kind(self_circuit_ID_t id);


#endif